package com.onesports.intelligent.k12.polarlight.service.sys;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.onesports.framework.kit.common.util.ParamUtils;
import com.onesports.intelligent.k12.polarlight.common.constant.Constants;
import com.onesports.intelligent.k12.polarlight.common.domain.entity.BaseEntity;
import com.onesports.intelligent.k12.polarlight.common.errors.exceptions.BusinessException;
import com.onesports.intelligent.k12.polarlight.domain.entity.sys.Menu;
import com.onesports.intelligent.k12.polarlight.domain.vo.common.AuthTreeVO;
import com.onesports.intelligent.k12.polarlight.enums.MenuType;
import com.onesports.intelligent.k12.polarlight.mapper.sys.AccountRoleMapper;
import com.onesports.intelligent.k12.polarlight.mapper.sys.MenuMapper;
import com.onesports.intelligent.k12.polarlight.mapper.sys.RoleMenuMapper;
import com.onesports.intelligent.k12.polarlight.constant.CacheConstants;
import com.onesports.intelligent.k12.polarlight.security.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Wsy
 **/
@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = CacheConstants.MENU, keyGenerator = "customCacheKeyGenerator")
public class MenuService extends ServiceImpl<MenuMapper, Menu> {

    private final MenuMapper menuMapper;
    private final AccountRoleMapper accountRoleMapper;
    private final RoleMenuMapper roleMenuMapper;

    /**
     * 添加菜单
     *
     * @param menu 菜单
     */
    @CacheEvict(allEntries = true)
    public void add(Menu menu) {
        //校验菜单名称
        this.checkMenuName(menu.getMenuName(), menu.getId(), menu.getSystemCode());
        this.dealWithMenuTypeAndLevel(menu);
        this.menuMapper.insert(menu);
    }


    /**
     * 处理菜单类型
     *
     * @param menu 菜单入参
     */
    private void dealWithMenuTypeAndLevel(Menu menu) {
        if (ParamUtils.isEmpty(menu.getParentId())) {
            menu.setMenuType(MenuType.MODULE.getValue());
            menu.setMenuLevel(MenuType.MODULE.getValue());
        } else {
            menu.setMenuType(MenuType.MENU.getValue());
            menu.setMenuLevel(MenuType.MENU.getValue());
        }
    }

    /**
     * 校验菜单名称
     *
     * @param router 菜单地址
     * @param id     菜单id
     */
    private void checkMenuName(String router, String id, String systemCode) {
        List<Menu> list = this.menuMapper.selectList(new QueryWrapper<Menu>().lambda()
//                .eq(Menu::getRouter, router)
                .eq(Menu::getMenuName, router)
                .eq(Menu::getSystemCode, systemCode)
                .ne(ParamUtils.isNotEmpty(id), BaseEntity::getId, id));
        if (ParamUtils.isNotEmpty(list)) {
            throw new BusinessException("该菜单已存在，请重新输入");
        }
    }

    /**
     * 修改菜单
     *
     * @param menu 菜单
     */
    @CacheEvict(allEntries = true)
    public void update(Menu menu) {
        this.checkMenuName(menu.getMenuName(), menu.getId(), menu.getSystemCode());
        this.dealWithMenuTypeAndLevel(menu);
        this.menuMapper.updateById(menu);
    }


    /**
     * 删除
     *
     * @param id 入参
     */
    @CacheEvict(allEntries = true)
    public void delete(String id) {
        //校验菜单
        List<Menu> list = this.menuMapper.selectList(new QueryWrapper<Menu>().lambda().eq(Menu::getParentId, id));
        if (ParamUtils.isNotEmpty(list)) {
            throw new BusinessException("该菜单下有子菜单不能进行删除操作！");
        }
        LambdaUpdateWrapper<Menu> update = new LambdaUpdateWrapper<Menu>()
                .set(BaseEntity::getDeleted, true)
                .eq(BaseEntity::getId, id);
        this.update(update);
    }


    /**
     * 获取所有菜单（过滤按钮）
     *
     * @return List<Menu>
     */
    @Cacheable
    public List<Menu> getAllList() {
        LambdaQueryWrapper<Menu> lambda = new QueryWrapper<Menu>().lambda();
        lambda.eq(BaseEntity::getDeleted, false);
        return this.menuMapper.selectList(lambda);
    }


    /**
     * 获取菜单权限树
     *
     * @param systemCode 系统编号
     * @return List<AuthTreeVO>
     */
    @Cacheable
    public List<AuthTreeVO> getTree(String systemCode) {
        List<Menu> menus = this.getMenuBySystemCode(systemCode);
        if (ParamUtils.isEmpty(menus)) {
            return new ArrayList<>();
        }
        return this.setTree(menus);
    }

    /**
     * 设置树
     *
     * @param menus 菜单s
     * @return List<AuthTreeVO>
     */
    public List<AuthTreeVO> setTree(List<Menu> menus) {
        Map<String, List<Menu>> menuMap = this.getMenuMap(menus);
        List<Menu> topNode = this.getTopNode(menus);
        return this.buildTree(menuMap, topNode);
    }

    /**
     * 封装权限树
     *
     * @param topNode 子树
     * @param menuMap k: sysCode, v: list
     * @return List<AuthTreeVO>
     */
    private List<AuthTreeVO> buildTree(Map<String, List<Menu>> menuMap, List<Menu> topNode) {
        List<AuthTreeVO> results = new ArrayList<>(16);
        if (ParamUtils.isNotEmpty(topNode)) {
            results = topNode.stream().map(i -> {
                List<AuthTreeVO> children = this.buildTree(menuMap, menuMap.get(i.getId()));
                return AuthTreeVO.builder()
                        .id(i.getId())
                        .label(i.getMenuName())
                        .sort(i.getSort())
                        .url(i.getRouter())
                        .menuUri(i.getMenuUri())
                        .children(children).build();
            }).collect(Collectors.toList());
        }
        return results;
    }


    /**
     * 获取菜单MAP
     *
     * @param menus 菜单data
     * @return Map<String, List < Menu>> k: pid  v: menuList
     */
    public Map<String, List<Menu>> getMenuMap(List<Menu> menus) {
        if (ParamUtils.isNotEmpty(menus)) {
            return menus.stream().collect(Collectors.groupingBy(Menu::getParentId));
        }
        return new HashMap<>(16);
    }


    /**
     * 过滤出pid为0 的数据
     *
     * @param menus 菜单data
     * @return List<Menu>
     */
    public List<Menu> getTopNode(List<Menu> menus) {
        if (ParamUtils.isNotEmpty(menus)) {
            return menus.stream().sorted(Comparator.comparing(Menu::getSort))
                    .filter(f -> f.getParentId().equals(Constants.TOP_PID_STR)).collect(Collectors.toList());
        }
        return new ArrayList<>(16);
    }


    /**
     * 获取菜单权限树
     *
     * @param accountId 账号id
     * @return List<AuthTreeVO>
     */
    public List<AuthTreeVO> getAuthMenuTree(String accountId, String systemCode) {
        return this.setTree(listMenuByAccountId(accountId, systemCode));

    }

    public List<Menu> listMenuByAccountId(String accountId, String systemCode) {
        return roleMenuMapper.listMenuByAccountId(accountId, systemCode,
                null, SecurityUtils.isSuper());
    }


    /**
     * 根据系统编号获取菜单
     *
     * @param systemCode 系统编号
     * @return List<Menu>
     */
    @Cacheable
    public List<Menu> getMenuBySystemCode(String systemCode) {
        return this.menuMapper.selectList(new QueryWrapper<Menu>().lambda()
                .in(Menu::getSystemCode, systemCode)
                .eq(BaseEntity::getDeleted, false)
                .orderByAsc(Menu::getSort).orderByAsc(BaseEntity::getCreatedDate));
    }
}
